package com.su.kddq.service.user.impl;

import com.alipay.easysdk.factory.Factory;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.su.kddq.constant.OrderStateConstant;
import com.su.kddq.constant.RabbitMqConstant;
import com.su.kddq.entity.courier.CourierOrder;
import com.su.kddq.entity.user.Order;
import com.su.kddq.entity.user.PayOrder;
import com.su.kddq.entity.user.School;
import com.su.kddq.entity.user.UserWallet;
import com.su.kddq.entity.user.vo.*;
import com.su.kddq.mapper.courier.CourierOrderMapper;
import com.su.kddq.mapper.user.OrderMapper;
import com.su.kddq.mapper.user.PayOrderMapper;
import com.su.kddq.mapper.user.SchoolMapper;
import com.su.kddq.mapper.user.UserWalletMapper;
import com.su.kddq.productor.OrderProductor;
import com.su.kddq.service.user.OrderService;
import com.su.kddq.utils.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @author sx
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private CourierOrderMapper courierOrderMapper;

    @Autowired
    private SchoolMapper schoolMapper;

    @Autowired
    private UserWalletMapper userWalletMapper;

    @Autowired
    private OrderProductor orderProductor;

    @Autowired
    private PayOrderMapper payOrderMapper;


    private static ReentrantLock lock = new ReentrantLock();


    @Override
    public IPage<Order> getOrderListPage(Integer pageNum, Integer pageSize, Integer orderState) {
        Calendar cal = Calendar.getInstance();
        List oIds;
        String id = SecurityContextHolder.getContext().getAuthentication().getName();
        //限制一下pageNum和pageSize不能为空，代码省略
        //实例化分页工具
        IPage<Order> page = new Page<>(pageNum, pageSize);
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        //实例化条件构造器
        if (orderState != -1 && orderState != 0) {
            if (orderState.equals(OrderStateConstant.ORDER_CANCEL)) {
                queryWrapper.eq("order_state", orderState);
            } else {
                queryWrapper.eq("order_state", orderState).eq("pay_state", OrderStateConstant.ORDER_PAY_STATE_YES);
            }
        } else if (orderState == 0) {
            queryWrapper.eq("pay_state", OrderStateConstant.ORDER_PAY_STATE_YES).ne("order_state", OrderStateConstant.ORDER_CANCEL).ne("order_state", OrderStateConstant.ORDER_SUC);
        }
        queryWrapper.eq("uid", id);
        queryWrapper.orderByDesc("create_time");
        //调用page方法
        IPage<Order> orderIPage = this.page(page, queryWrapper);
        oIds = orderIPage.getRecords().stream().map(Order::getOrderId).collect(Collectors.toList());
        if (oIds.size() != 0) {
            List<CourierOrder> courierOrders = courierOrderMapper.selectList(new QueryWrapper<CourierOrder>().select("creat_time", "order_id").in("order_id", oIds));
            for (Order order : orderIPage.getRecords()) {
                for (CourierOrder courierOrder : courierOrders) {
                    if (courierOrder.getOrderId().equals(order.getOrderId())) {
                        cal.setTime(courierOrder.getCreatTime());
                        if (order.getIsFast().equals(0)) {
                            cal.add(Calendar.HOUR, 1);
                        } else {
                            cal.add(Calendar.MINUTE, 35);
                        }
                        order.setFutureTime(cal.getTime());
                    }
                }
            }
        }
        return orderIPage;
    }

    @Override
    public Map getOrderListNoPage(Map map) {
        String uid = SecurityContextHolder.getContext().getAuthentication().getName();
        map.put("uid", uid);
        DecimalFormat decimalFormat = new DecimalFormat(".00");
        List<SendOrder> orderListNoPage = orderMapper.getOrderListNoPage(map);
        Integer total = orderMapper.getOrderListTotal(uid);
        List<SendOrder> orderList = orderListNoPage.stream().map((order) -> {
            order.setOrderPrice(decimalFormat.format((Float.parseFloat(order.getOrderPrice()) * OrderStateConstant.ORDER_CCL)));
            return order;
        }).collect(Collectors.toList());
        map.put("total", total);
        map.put("orderList", orderList);
        return map;
    }

    /**
     * 抢单逻辑
     */
    @Override
    public boolean orderGrabbing(String id) {
        lock.lock();
        try {
            DecimalFormat decimalFormat = new DecimalFormat(".00");
            Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("order_id", id));
            CourierOrder courierOrderInfo = courierOrderMapper.selectOne(new QueryWrapper<CourierOrder>().eq("order_id", id));
            if (courierOrderInfo == null) {
                String cid = SecurityContextHolder.getContext().getAuthentication().getName();
                CourierOrder courierOrder = new CourierOrder();
                courierOrder.setOrderId(order.getOrderId());
                courierOrder.setCreatTime(new Date());
                courierOrder.setUpdateTime(new Date());
                courierOrder.setQjyOrderMoney(Float.valueOf(decimalFormat.format(Float.parseFloat(order.getOrderPrice()) * OrderStateConstant.ORDER_CCL)));
                courierOrder.setUid(order.getUid());
                courierOrder.setIsTx(OrderStateConstant.ORDER_TX_NO);
                courierOrder.setCid(Integer.valueOf(cid));
                courierOrder.setIsExpired(OrderStateConstant.NO_ORDER_EXPIRED);
                courierOrderMapper.insert(courierOrder);
                order.setOrderState(OrderStateConstant.ORDER_DQJ);
                orderMapper.updateById(order);
                //向mq发送消息推送
                Map map = new HashMap();
                map.put("uid", order.getUid());
                map.put("orderState", order.getOrderState());
                map.put("orderId", order.getOrderId());
                orderProductor.SendOrderMes(map, RabbitMqConstant.EXCHANGE_MSG_CID, RabbitMqConstant.ROUTING_KEY_MSG);
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Map getPendingOrder(Integer pageNum, Integer pageSize) {
        try {
            Map map = new HashMap();
            Calendar cal = Calendar.getInstance();
            Date updateTime = new Date();
            String cid = SecurityContextHolder.getContext().getAuthentication().getName();
            map.put("cid", cid);
            map.put("pageNum", pageNum);
            map.put("pageSize", pageSize);
            List<PendingOrderVo> orders = orderMapper.getPendingOrder(map);
            Integer total = orderMapper.getPendingOrderTotal(cid);
            List<PendingOrderVo> collect = orders.stream().map(order -> {
                cal.setTime(order.getCreatTime());
                if (order.getIsFast() == 0) {
                    cal.add(Calendar.HOUR, 1);
                } else {
                    cal.add(Calendar.MINUTE, 35);
                }
                order.setExpiredTime(String.valueOf(cal.getTimeInMillis() - updateTime.getTime()));
                return order;
            }).collect(Collectors.toList());
            map.put("total", total);
            map.put("orderList", collect);
            return map;
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }

    @Override
    @Transactional(
            rollbackFor = {Exception.class}
    )
    public void updateOrderStatus(String id) {
        Date updateTime = new Date();
        Calendar cal = Calendar.getInstance();
        try {
            Order order = orderMapper.selectOne((new QueryWrapper<Order>().eq("order_id", id)));
            CourierOrder courierOrder = courierOrderMapper.selectOne(new QueryWrapper<CourierOrder>().eq("order_id", id));
            if (order.getOrderState().equals(OrderStateConstant.ORDER_DQJ)) {
                order.setOrderState(OrderStateConstant.ORDER_PSZ);
            } else if (order.getOrderState().equals(OrderStateConstant.ORDER_PSZ)) {
                cal.setTime(courierOrder.getCreatTime());
                if (order.getIsFast().equals(OrderStateConstant.NO_ORDER_FAST)) {
                    cal.add(Calendar.HOUR, 1);
                } else {
                    cal.add(Calendar.MINUTE, 35);
                }
                //判断是否为超时订单
                boolean is_expired = order.getIsFast().equals(OrderStateConstant.NO_ORDER_FAST)
                        && updateTime.getTime() > cal.getTimeInMillis() ||
                        order.getIsFast().equals(OrderStateConstant.YES_ORDER_FAST)
                                && updateTime.getTime() > cal.getTimeInMillis();
                if (is_expired) {
                    //超时订单罚率20%
                    courierOrder.setQjyOrderMoney(courierOrder.getQjyOrderMoney() * OrderStateConstant.ORDER_EXPIRED);
                    courierOrder.setIsExpired(OrderStateConstant.YES_ORDER_EXPIRED);
                }
                order.setOrderState(OrderStateConstant.ORDER_SUC);
            } else {
                log.error("订单状态错误");
                throw new RuntimeException("订单状态错误");
            }
            orderMapper.updateById(order);
            courierOrderMapper.updateById(courierOrder);
            //向mq发送订单状态更新消息推送
            Map map = new HashMap();
            map.put("uid", order.getUid());
            map.put("orderState", order.getOrderState());
            map.put("orderId", order.getOrderId());
            orderProductor.SendOrderMes(map, RabbitMqConstant.EXCHANGE_MSG_CID, RabbitMqConstant.ROUTING_KEY_MSG);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public Map creatOrder(Order order) {
        Map map = new HashMap();
        try {
            boolean is_bad = order.getBigType().equals(OrderStateConstant.KD_ORDER_TYPE)
                    && Float.parseFloat(order.getOrderPrice()) < OrderStateConstant.ORDER_START_PRICE ||
                    order.getBigType().equals(OrderStateConstant.PT_ORDER_TYPE) &&
                            Float.parseFloat(order.getOrderPrice()) < OrderStateConstant.PT_START_PRICE;
            if (is_bad) {
                //订单金额小于起步金额 怀疑恶意请求
                //TODO 接入风控
                map.put("isCreat", false);
                map.put("code", ResultCode.BAD_REQUEST);
                return map;
            }
            UserWallet userWallet = userWalletMapper.selectOne(new QueryWrapper<UserWallet>().select("balance").eq("uid", order.getUid()));
            //余额不足
            if (Float.parseFloat(order.getOrderPrice()) / 100 > userWallet.getBalance()) {
                map.put("isCreat", false);
                map.put("code", ResultCode.NO_BALANCE);
                return map;
            }
            School school = schoolMapper.selectOne(new QueryWrapper<School>().select("school_id").eq("uid", order.getUid()));
            List<Integer> schoolIds = schoolMapper.querySchoolIdsAndcourierStatus(order.getUid());
            if (!schoolIds.contains(school.getSchoolId())) {
                //没有可以调度的取件员
                map.put("isCreat", false);
                map.put("code", ResultCode.NO_SCHEDULE);
                return map;
            }
            order.setOrderId(UUID.randomUUID().toString().replace("-", ""));
            order.setOrderState(OrderStateConstant.ORDER_DFP);
            order.setPayState(OrderStateConstant.ORDER_PAY_STATE_NO);
            order.setOrderPrice(String.valueOf(Float.parseFloat(order.getOrderPrice()) / 100));
            order.setCreateTime(new Date());
            order.setUpdateTime(new Date());
            this.save(order);
            map.put("isCreat", true);
            return map;
        } catch (Exception e) {
            log.error("下单接口异常" + e.getMessage());
            map.put("isCreat", false);
            map.put("code", ResultCode.ERROR);
            return map;
        }
    }

    @Override
    public OrderDetail getOrderDetailByid(String id) {
        Order order = this.getOne(new QueryWrapper<Order>().eq("order_id", id));
        CourierVo courierVo = courierOrderMapper.queryCourierBycid(id);
        OrderDetail orderDetail = new OrderDetail();
        BeanUtils.copyProperties(order, orderDetail);
        orderDetail.setCourierVo(courierVo);
        return orderDetail;
    }

    @Override
    public String payNotify(HttpServletRequest request) {
        SortedMap paramMap = new TreeMap<>();
        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
        entrySet.stream().forEach(item -> paramMap.put(item.getKey(), item.getValue()[0]));
        try {
            //调用esaysdk中verifyNotify()进行主动验签
            Boolean aBoolean = Factory.Payment.Common().verifyNotify(paramMap);
            if (aBoolean && "TRADE_SUCCESS".equals(paramMap.get("trade_status"))) {
                Map<String, Object> msgMap = new HashMap();
                msgMap.put("payOrderId", paramMap.get("out_trade_no"));
                msgMap.put("money", paramMap.get("total_amount"));
                msgMap.put("trade_no",paramMap.get("trade_no"));
                orderProductor.SendOrderMes(msgMap, RabbitMqConstant.EXCHANGE_ORDER, RabbitMqConstant.ROUTING_KEY);
                return "success";
            } else {
                return "failure";
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return "failure";
        }
    }

    @Override
    public boolean payOrder(Order order) {
        try {
            Order newOrder = orderMapper.selectOne(new QueryWrapper<Order>().eq("order_id", order.getOrderId()));
            float orderPrice = Float.parseFloat(newOrder.getOrderPrice());
            UserWallet userWallet = userWalletMapper.selectOne(new QueryWrapper<UserWallet>().eq("uid", newOrder.getUid()));
            //二次判断订单金额是否小于余额，防止恶意请求
            if (userWallet.getBalance() < orderPrice) {
                return false;
            }
            userWallet.setBalance(userWallet.getBalance() - orderPrice);
            userWalletMapper.updateById(userWallet);
            newOrder.setPayState(OrderStateConstant.ORDER_PAY_STATE_YES);
            orderMapper.updateById(newOrder);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    @Override
    public boolean cancelOrder(Map map) {
        try {
            Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("order_id", map.get("orderId")));
            if (order.getOrderState() >= OrderStateConstant.ORDER_CANCEL) {
                //已经退单的/配送中/结单不能再次退单
                return false;
            }
            if (order.getPayState().equals(OrderStateConstant.ORDER_PAY_STATE_YES)) {
                //分配中并且已支付的订单费用退回余额
                UserWallet userWallet = userWalletMapper.selectOne(new QueryWrapper<UserWallet>().eq("uid", order.getUid()));
                userWallet.setBalance(userWallet.getBalance() + Float.parseFloat(order.getOrderPrice()));
                userWalletMapper.updateById(userWallet);
                //支付状态改成1
                order.setPayState(OrderStateConstant.ORDER_PAY_STATE_NO);
            }
            //将订单状态改为2
            order.setOrderState(OrderStateConstant.ORDER_CANCEL);
            orderMapper.updateById(order);
            return true;
        } catch (NumberFormatException e) {
            log.error(e.getMessage());
            return false;
        }
    }

    @Override
    public Map getMoneybyMonthList(Integer pageNum, Integer pageSize) {
        Map wrapper = new HashMap();
        String cid = SecurityContextHolder.getContext().getAuthentication().getName();
        wrapper.put("pageNum", pageNum);
        wrapper.put("pageSize", pageSize);
        wrapper.put("cid", cid);
        List<HistoryOrder> moneybyMonthList = orderMapper.getMoneybyMonthList(wrapper);
        Integer total = orderMapper.getMoneybyMonthTotal(wrapper);
        wrapper.put("total", total);
        wrapper.put("list", moneybyMonthList);
        return wrapper;
    }

    @Override
    public PayOrder payResult(String payOrderId) {
        PayOrder payOrder = payOrderMapper.selectOne(new QueryWrapper<PayOrder>().eq("pay_order_id", payOrderId));
        return payOrder;
    }


}
